                                                                     
                                                                     
                                                                     
                                             
import japa.parser.JavaParser;

import japa.parser.ast.CompilationUnit;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.expr.AssignExpr;
import japa.parser.ast.expr.FieldAccessExpr;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.ObjectCreationExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import japa.parser.ast.visitor.VoidVisitorAdapter;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
public class ClassCouplingParser {
	static BufferedWriter classNames;
	static BufferedWriter classIns;	
	static String [ ]objectCreationExpression=new String[1000];
	static String [ ]instanceExpr=new String[1000];
	static int noOfObject=0;	
	static int noOfInstanceExpr=0;
	static String classInstanceExprFormat=null;
	static String[] ClassNames;
	static int index;
	static int numOfFiles;
	
	public void parseClasses(String[] filenames, int numFiles) throws Exception {
		    	
		CompilationUnit[] cu=new CompilationUnit[1000];
	     FileInputStream[] in=new FileInputStream[1000];
	      ClassNames=new String[numFiles];
	      numOfFiles=numFiles; 
	     
	     for(int j=0;j<numFiles;j++){
	    	 in[j] = new FileInputStream(filenames[j]); 
	    
	    }
			    
				for(int j=0;j<numFiles;j++){
			    	 in[j] = new FileInputStream(filenames[j]);
			    	 
			    }
			      		        
		        classNames = new BufferedWriter(new FileWriter("InfoFiles/classNames.txt"));
		        classIns = new BufferedWriter(new FileWriter("InfoFiles/Instantiation.txt"));
		        
		        try {
		        	for(int j=0;j<numFiles;j++){
		        		cu[j] = JavaParser.parse(in[j]); 
		        	}
		        } finally {
		        	
		        	
		        	
		        for(int k=0; k<numFiles; k++)
		        	{
		        		in[k].close();
		        	}
		            
		        }
		       
		        
		        for(int i=0;i<numFiles;i++){
		        	
		        	index=i;
		        	new ClassVisitor1().visit(cu[i], null);
		        	
		         }
		        
		        
		        for(int i=0;i<numFiles;i++){
		        	
		        
		        	System.out.println("classNames"+ClassNames[i]);
		        	
		         }
		        
		       
		        
		        
		        for(int i=0; i<numFiles; i++){	
		        	
		        	//Get Local Class Instantiations Expression for instance, " className object = new className();"
		            new LocalClassInstantiationVisitor().visit(cu[i], null);
		        	
		        	//Get Class Names and stores it in classNames.txt file  
		        	new ClassVisitor().visit(cu[i], null);
		        	
		        	//Get Class Instantiations Expression for instance, " className object = new className();"
		        	new ClassInstantiationExpr().visit(cu[i],null);
		        	
		        	//Get Object Creation Expression for instance, "object = new className();"  
		        	new ObjectCreationVisitor().visit(cu[i],null);
		        	
		        	//Get Object Name Expressions for instance, "new className();" 	        	
		        	new ObjectNameVisitor().visit(cu[i],null);		        	
		        	
		        	//Get fields Accessed by an object			        	
		        	new FieldAccessVisitor().visit(cu[i], null);
		        	
		        	//Get Methods Invoked by an object		        	
		        	new MethodInvocationVisitor().visit(cu[i],null);
		        	
		        	//place delimiter		        	 
		        	classIns.write("End of File");
		        	classIns.newLine();
		        	noOfObject=0;	
		        	noOfInstanceExpr=0;
		        }
		        classNames.close();
		        classIns.close();
	}

		   
	private static class ClassVisitor1 extends VoidVisitorAdapter<Object> {

        @Override
		public void visit(ClassOrInterfaceDeclaration  n, Object arg) {
     	
               			
        			System.out.println("Class Visitor "+n.getName());
        			ClassNames[index]=(n.getName());
        		
				
          } 


        
	}
	
	
	
	
	private static class ClassVisitor extends VoidVisitorAdapter<Object> {

        @Override
		public void visit(ClassOrInterfaceDeclaration  n, Object arg) {
     	
        	try {        			
        			System.out.println("Class Visitor "+n.getName());
        			classNames.write(n.getName());
        			classNames.newLine();
				} catch (IOException e) {					
					e.printStackTrace();
			}
          
        } 


        
	}
	 /*
     * "visit(...)" method returns class members that are 
     * instantiating an object, For Instance, 
     * className object=new className(); changeFormat Bring 
     * this into format className object;  
     */
    private static class LocalClassInstantiationVisitor extends VoidVisitorAdapter<Object> {

    	public String changeFormatToInstanceExpr(String expr)
		{	
    		int index=0;
    		String instantiatedClass=null;
			String instanceName=null;	
			String[] names=expr.split(" ");
			for(int i=0; i<names.length; i++)
			{
				//System.out.println("Expression 1 "+i+" "+names[i]);	
			}			
			if(names.length>4)
			{
				index=names.length-5;
			}
			instantiatedClass=names[index];
			instanceName=names[index+1];
			//System.out.println("Class Expr "+instantiatedClass+" "+instanceName);
			return instantiatedClass+" "+instanceName; //returns the result in the form "className object"
		
		}	        
        @Override
		public void visit(FieldDeclaration n, Object arg) {
     	
        	try {		
        		
        		String declaredFields=n.toString();        		
        		if(declaredFields.contains(" new")){
        			classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());
        			instanceExpr[noOfInstanceExpr++]=new String(classInstanceExprFormat);        			
        		}		        	
			} catch (Exception e) {					
				e.printStackTrace();
			}		          
        }		        
    }

	 /*
	 *  "visit()" method in this class visits all   
	 *  instantiating expression "className object=new className()" within methods
	 *  and stores "className object" in instanceExpr array	     
	 */
	private static class ClassInstantiationExpr extends VoidVisitorAdapter<Object> {

		public String changeFormatToInstanceExpr(String expr)
		{			
							
			int index=0;
    		String instantiatedClass=null;
			String instanceName=null;	
			String[] names=expr.split(" ");
			for(int i=0; i<names.length; i++)
			{
				//System.out.println("Expression 1 "+i+" "+names[i]);	
			}			
			if(names.length>4)
			{
				index=names.length-5;
			}
			instantiatedClass=names[index];
			instanceName=names[index+1];
			//System.out.println("Class Expr "+instantiatedClass+" "+instanceName);
			return instantiatedClass+" "+instanceName; //returns the result in the form "className object
		
		}  
	
		@Override
		public void visit(VariableDeclarationExpr  n, Object arg) {
     	
        	try {
        		
        			super.visit(n, arg);        	
        			classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());        			
        			instanceExpr[noOfInstanceExpr++]=new String(classInstanceExprFormat);
        			
        			
			} 	catch (Exception e) {					
						e.printStackTrace();
			}
          
        } 
	}

	/*
	 * "visit()" method in this class stores all 
	 * object creation expression "new className()" in the array objectCreationExpression
	 */
	
	private static class ObjectCreationVisitor extends VoidVisitorAdapter<Object> {

       
		@Override
		public void visit(ObjectCreationExpr n, Object arg) {
     	
        	try {        		        			
    			    
        			objectCreationExpression[noOfObject++]=new String(n.toString());        			
        		
			}catch (Exception e) {					
						e.printStackTrace();
			}
          
        } 
    
	}
	 /*
     * "visit()" method evaluates all assignment expressions in the class and
     * uses objectCreationExpression array to find out an assignment that 
     * is used to create an instance of the object for instance object = new className();
     * "object=new className()" is the assignment expression as well as it is instantiating 
     * an instance for a class"
     */
    
	private static class ObjectNameVisitor extends VoidVisitorAdapter<Object> {
		public String changeFormatToInstanceExpr(String expr)
		{		
			int index=0;
    		String instantiatedClass=null;
			String instanceName=null;	
			String[] names=expr.split(" ");
			for(int i=0; i<names.length; i++)
			{
				//System.out.println("Expression 1 "+i+" "+names[i]);	
			}			
			if(names.length>4)
			{
				index=names.length-5;
			}
			instantiatedClass=names[index];
			instanceName=names[index+1];
			//System.out.println("Class Expr "+instantiatedClass+" "+instanceName);
			return instantiatedClass+" "+instanceName; //returns the result in the form "className object
		
		}
        @Override
		public void visit(AssignExpr n, Object arg) {
     	
        	try {
        			String expression=n.toString();        		
        			for(int i=0; i<noOfObject; i++){
        			
        				if(expression.contains(objectCreationExpression[i]))        						
        				{   
        					classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());
        					instanceExpr[noOfInstanceExpr]=new String(classInstanceExprFormat);
        					
        					noOfInstanceExpr++;
        				}
        			}
        		
			} 	catch (Exception e) {					
						e.printStackTrace();
				}
          
        } 
    
	}

	/*
	 * "visit()" method in this class is getting fields accessed by an object "object.fieldAccessed"	  
	 */
	private static class FieldAccessVisitor extends VoidVisitorAdapter<Object> {
		
		 @Override
		public void visit(FieldAccessExpr  n, Object arg) {
		        	
		        	try {
		        			super.visit(n, arg);
		        			String fieldAccessed=n.toString();
		        			String field=n.getField();      			
		        			String fieldClassName=fieldAccessed.substring(0,fieldAccessed.indexOf("."));		        			
		        			for(int i=0; i<noOfInstanceExpr; i++){
		        				
		        				String className=instanceExpr[i].substring(0, instanceExpr[i].indexOf(" "));		        				
		        				String instanceName=instanceExpr[i].substring(instanceExpr[i].indexOf(" ")+1, instanceExpr[i].length());
			        			/*Compare fieldAccessed expression "object.fieldAccessed" with "className object" expression
			        			* to make it "className.fieldAccessed"
			        			*/ 
		        				if(fieldClassName.contentEquals(instanceName))
		        				{
		        					
		        					boolean flag=false;
	        						
	        						for(int l=0;l<numOfFiles;l++){
	        							
	        						    if(ClassNames[l]!=null && ClassNames[l].compareTo(className)==0){
	        						    	
	        						       flag=true;
	        						    
	        						    }
	        						
	        						}
		        					
		        					if(flag==true){
		        					classIns.write(className+"."+field);
		                			classIns.newLine();
		        					}
		        				}	
		        			}	
		        			
						} catch (IOException e) {					
							e.printStackTrace();
						}
		          
		        	}

	

		        
		    } 

	/*
	 * "visit()" method in this class is getting fields accessed by an object "object.fieldAccessed"	  
	 */	  

	private static class MethodInvocationVisitor extends VoidVisitorAdapter<Object> {

		        @Override
				public void visit(MethodCallExpr  n, Object arg) {
 	        	
		        	try {
		        			super.visit(n, arg);
		        			String fieldAccessed=n.toString();
		        			String field=n.getName()+"()";
		        			String fieldClassName=null;
		        			if(fieldAccessed.indexOf(".")>0){		        				
		        				fieldClassName=fieldAccessed.substring(0,fieldAccessed.indexOf("."));
		        			}
		        			/*Compare methodAccessed expression "object.methodAccessed" with "className object" expression
		        			* to make it "className.methodAccessed"
		        			*/ 		        			
		        			for(int i=0; i<noOfInstanceExpr; i++)
		        			{
		        				String className=instanceExpr[i].substring(0, instanceExpr[i].indexOf(" "));		        				
		        				String instanceName=instanceExpr[i].substring(instanceExpr[i].indexOf(" ")+1, instanceExpr[i].length());
		        				if(fieldClassName!=null && instanceName!=null)
		        				{
		        					if(fieldClassName.contentEquals(instanceName))
		        					{
		        						
		        						boolean flag=false;
		        						
		        						for(int l=0;l<numOfFiles;l++){
		        							
		        						    if(ClassNames[l]!=null && ClassNames[l].compareTo(className)==0){
		        						    	
		        						       flag=true;
		        						    
		        						    }
		        						
		        						}
		        						
		        						if(flag==true){
		        						  classIns.write(className+"."+field);
		        						  classIns.newLine();
		        						}
		        						
		        						}
		        				}
		        			}
		        			
					} 	catch (IOException e) {					
								e.printStackTrace();
						}
		          
		        } 
	}
		    
		    
		    
		    

}


